package ostt1_TokenLib;

import iaik.asn1.ASN;
import iaik.asn1.ASN1Object;
import iaik.asn1.CodingException;
import iaik.asn1.DerCoder;
import iaik.asn1.OCTET_STRING;
import iaik.asn1.ObjectID;
import iaik.asn1.structures.AlgorithmID;
import iaik.asn1.structures.Attribute;
import iaik.asn1.structures.ChoiceOfTime;
import iaik.asn1.structures.Name;
import iaik.pkcs.PKCSException;
import iaik.pkcs.pkcs10.CertificateRequest;
import iaik.pkcs.pkcs11.DefaultInitializeArgs;
import iaik.pkcs.pkcs11.Mechanism;
import iaik.pkcs.pkcs11.MechanismInfo;
import iaik.pkcs.pkcs11.Module;
import iaik.pkcs.pkcs11.Session;
import iaik.pkcs.pkcs11.Slot;
import iaik.pkcs.pkcs11.Token;
import iaik.pkcs.pkcs11.TokenException;
import iaik.pkcs.pkcs11.TokenInfo;
import iaik.pkcs.pkcs11.UnsupportedAttributeException;
import iaik.pkcs.pkcs11.objects.DHPrivateKey;
import iaik.pkcs.pkcs11.objects.DSAPrivateKey;
import iaik.pkcs.pkcs11.objects.Key;
import iaik.pkcs.pkcs11.objects.KeyPair;
import iaik.pkcs.pkcs11.objects.Object;
import iaik.pkcs.pkcs11.objects.PrivateKey;
import iaik.pkcs.pkcs11.objects.RSAPrivateKey;
import iaik.pkcs.pkcs11.objects.RSAPublicKey;
import iaik.pkcs.pkcs11.objects.X509PublicKeyCertificate;
import iaik.pkcs.pkcs11.wrapper.CK_ATTRIBUTE;
import iaik.pkcs.pkcs11.wrapper.PKCS11;
import iaik.pkcs.pkcs11.wrapper.PKCS11Constants;
import iaik.pkcs.pkcs11.wrapper.PKCS11Exception;
import iaik.pkcs.pkcs7.DigestInfo;
import iaik.pkcs.pkcs7.IssuerAndSerialNumber;
import iaik.pkcs.pkcs7.SignedData;
import iaik.pkcs.pkcs7.SignerInfo;
import iaik.security.provider.IAIK;
import iaik.utils.RFC2253NameParser;
import iaik.utils.RFC2253NameParserException;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.security.AccessController;
import java.security.GeneralSecurityException;
import java.security.InvalidKeyException;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.security.NoSuchProviderException;
import java.security.PrivilegedAction;
import java.security.Provider;
import java.security.PublicKey;
import java.security.Security;
import java.security.Signature;
import java.security.SignatureException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.security.interfaces.DSAParams;
import java.security.interfaces.RSAKey;
import java.security.spec.InvalidKeySpecException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Calendar;
import java.util.Collection;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Random;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.SecretKeyFactory;
import javax.crypto.spec.DESKeySpec;
import javax.crypto.spec.DHParameterSpec;
import javax.xml.bind.DatatypeConverter;
/*
 import org.bouncycastle.cert.X509CertificateHolder;
 import org.bouncycastle.cms.CMSException;
 import org.bouncycastle.cms.CMSProcessableByteArray;
 import org.bouncycastle.cms.CMSSignedData;
 import org.bouncycastle.cms.SignerInformation;
 import org.bouncycastle.cms.SignerInformationStore;
 import org.bouncycastle.cms.jcajce.JcaSimpleSignerInfoVerifierBuilder;
 import org.bouncycastle.jce.provider.BouncyCastleProvider;
 import org.bouncycastle.operator.OperatorCreationException;
 import org.bouncycastle.util.Store;
 */
import ostt1_TokenLib.ASNtype.tlvINT;
import ostt1_TokenLib.ASNtype.tlvNULL;
import ostt1_TokenLib.ASNtype.tlvOID;
import ostt1_TokenLib.ASNtype.tlvOctetString;
import ostt1_TokenLib.ASNtype.tlvOctetString81;
import ostt1_TokenLib.ASNtype.tlvOctetStringLong;
import ostt1_TokenLib.ASNtype.tlvSET;
import ostt1_TokenLib.ASNtype.tlvSETlong;
import ostt1_TokenLib.ASNtype.tlvSElong;
import ostt1_TokenLib.ASNtype.tlvSEshort;
import ostt1_TokenLib.ASNtype.tlvUTCTime;
import ostt1_TokenLib.ASNtype.tlvZero;
import ostt1_TokenLib.ASNtype.tlvZeroLong;
import ostt1_TokenLib.ASNtype.tlv_long;
import tomica.exception.PKCS11Exception_Tomica_ext;

public class ostt1_TokenLib {

    private static byte[] CRC32OK = {(byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x00};
    protected static Session session_;
    public static PKCS11 myPKCS11Module_;
    private static Module module_;
    private static Slot[] slots_;
    private static Token token_;
    private static PKCS11 modulePKCS11_;
    private static int MAX_OBJS = 16;
    private static String LIBS_CSP = "Vina-CAv3.dll"; //ostt1_csp11.dll
    private static String LIBS_WRAPPER = "PKCS11Wrapper";
    private static String PATH32 = "/wrapper32/";
    private static String PATH64 = "/wrapper64/";
    public static KeyPairGenerator keyGen;
    static PrintWriter output_;
    static BufferedReader input_;
    
    private static CK_ATTRIBUTE[] ckAttributeSave;

    static {
        try {
            output_ = new PrintWriter(System.out, true);
            input_ = new BufferedReader(new InputStreamReader(System.in));
        } catch (Throwable thr) {
            thr.printStackTrace();
            output_ = new PrintWriter(System.out, true);
            input_ = new BufferedReader(new InputStreamReader(System.in));
        }
    }

    public static int testConnectToken() throws TokenException, GeneralSecurityException, IOException, Exception {
        int status = ostt1_TokenLib.p11initialize();
        if (status == 1) {
            System.out.println("load library ok");
            if (ostt1_TokenLib.connectToken() != -1) {
                return 1;
            }
        } else {
            System.out.println("status: " + status);
        }
        return 0;


        //getContainerByID("");

        /*
         String SN = ostt1_TokenLib.GetSerialNumber();
         System.out.println("SN: = "+SN);
		
         if(ostt1_TokenLib.Login("12345678".toCharArray()))
         System.out.println("login ok");
         else
         System.out.println("login fail");
         System.out.println("Gen csr...");
         System.out.println(genCSR("39464143304141382D373332412D344433452D393937332D3135393642343146354330453100", "C=VN, CN=test gen csr, O=tomica, OU=tomicalab, ST=HCM, L=Q1"));
         */
//		RSAPrivateKey privateKey = getPrivateKeyPair(0);
//		
//		byte[] sign = signpkcs7("Hello", 0, privateKey);
//		System.out.println(DatatypeConverter.printBase64Binary(sign));

        //getX509CertificateObject(0);
        //getX509CertificateObject(1);

//		getPrivateKeyByID("asa");
//		System.out.println("Certificate ID");
//		GetCertificateID();

//		String SN = "2013062800090";
//		//String RN = genRN(SN);
//		String RN = "b3N0dDFfnsnfPRdvlzZ0ikHdTpm/HusantaCEQsdM5yzo4HQl/c=";
//		//System.out.println("RN = "+DatatypeConverter.parseBase64Binary(RN));
//		
//		String SN1 = getSN(RN);
//		System.out.println("SN = "+SN1);
//		
//		String plainPIN = "12345678";
//		String EncodedPIN = encodeSOPIN(plainPIN);
//		System.out.println("Encoded SOPIN: "+EncodedPIN);
//		
//		String DecodedPIN = decodeSOPIN(EncodedPIN);
//		System.out.println("Decoded SOPIN: "+DecodedPIN);
//		
//		String UC = genUC(EncodedPIN, RN);
//		System.out.println("UC = "+UC);

//		String SO = getSO("V3AQI0m1rLxIdHs0VWWvjUcRsOGuI6ZsA9lptXIdyYHT0j+wGXbkOxelycI4R29ThwvaTO9wtpxjAXUhDOskjrHTFUPuCVqY+WNHmUJpgLjv8d5N/zewBQ==");
//		System.out.println("SO = "+SO);


    }

    public static void test() throws GeneralSecurityException, IOException, TokenException, CodingException, PKCSException {
        byte[] data = "Hello".getBytes("UTF-16LE");
//		InputStream dataInputStream = new FileInputStream(args[1]);
//
//		// we do digesting outside the card, because some cards do not support on-card hashing
        MessageDigest digestEngine = MessageDigest.getInstance("SHA-1");

//		// we buffer the content to have it after hashing for the PKCS#7 content
//		ByteArrayOutputStream contentBuffer = new ByteArrayOutputStream();
//		byte[] dataBuffer = new byte[1024];
//		int bytesRead;
//
//		// feed all data from the input stream to the message digest
//		while ((bytesRead = dataInputStream.read(dataBuffer)) >= 0) {
//			// hash the data
//			digestEngine.update(dataBuffer, 0, bytesRead);
//			// and buffer the data
//			contentBuffer.write(dataBuffer, 0, bytesRead);
//		}
        digestEngine.update(data);
        byte[] contentHash = digestEngine.digest();
        //contentBuffer.close();

        // create the SignedData
        SignedData signedData = new SignedData(data, SignedData.EXPLICIT);

        iaik.x509.X509Certificate signerCertificate = new iaik.x509.X509Certificate(getX509CertificateObject(0).getEncoded());

        // set the certificates
        signedData.setCertificates(new iaik.x509.X509Certificate[]{signerCertificate});

        // create a new SignerInfo
        SignerInfo signerInfo = new SignerInfo(new IssuerAndSerialNumber(signerCertificate),
                AlgorithmID.sha1, null);

        // define the authenticated attributes
        iaik.asn1.structures.Attribute[] authenticatedAttributes = {
            new Attribute(ObjectID.contentType, new ASN1Object[]{ObjectID.pkcs7_data}),
            new Attribute(ObjectID.signingTime,
            new ASN1Object[]{new ChoiceOfTime().toASN1Object()}),
            new Attribute(ObjectID.messageDigest, new ASN1Object[]{new OCTET_STRING(
                contentHash)})};
        // set the authenticated attributes
        signerInfo.setAuthenticatedAttributes(authenticatedAttributes);

        // encode the authenticated attributes, which is the data that we must sign
        byte[] toBeSigned = DerCoder.encode(ASN.createSetOf(authenticatedAttributes, true));

        // we do digesting outside the card, because some cards do not support on-card hashing
        // we can use the digest engine from above
        byte[] hashToBeSigned = digestEngine.digest(toBeSigned);

        // according to PKCS#11 building the DigestInfo structure must be done off-card
        DigestInfo digestInfoEngine = new DigestInfo(AlgorithmID.sha1, hashToBeSigned);

        byte[] toBeEncrypted = digestInfoEngine.toByteArray();

        PrivateKey selectedSignatureKey = (PrivateKey) getPrivateKeyPair(0);
        // initialize for signing
        session_.signInit(Mechanism.get(PKCS11Constants.CKM_RSA_PKCS), selectedSignatureKey);

        // sign the data to be signed
        byte[] signatureValue = session_.sign(toBeEncrypted);

        // set the signature value in the signer info
        signerInfo.setEncryptedDigest(signatureValue);

        // and add the signer info object to the PKCS#7 signed data object
        signedData.addSignerInfo(signerInfo);
        System.out.println(DatatypeConverter.printBase64Binary(signedData.getEncoded()));
    }

    /**
     * this function use to test hSession from client is true
     * @param hSession
     * @throws PKCS11Exception_Tomica_ext if hsession don't match
     */
    private static void to_ext_CheckHSession(long hSession ) throws PKCS11Exception_Tomica_ext{
        if (session_.getSessionHandle() != hSession) {
            throw new PKCS11Exception_Tomica_ext(PKCS11Constants.CKR_TOMICA_SESSIONHANDLE_INCORRECT, "0x00001004L");
        }
    }
    
    public static int p11initialize() throws IOException, PKCS11Exception {

        String dllwrapper;
        dllwrapper = loadDll(LIBS_WRAPPER);
        module_ = Module.getInstance(LIBS_CSP, dllwrapper);
        module_.initialize(new DefaultInitializeArgs());
        return 1;
    }

    /**
     * to = tomica
     *
     * @tcchtnn hien thu ham goi getSlotList tcchtnn
     * @param tokenPresent
     * @return
     * @throws PKCS11Exception
     */
    public static long[] toCGetSlotList(boolean tokenPresent) throws PKCS11Exception {
        slots_ = module_.getSlotList(Module.SlotRequirement.TOKEN_PRESENT);
        long[] slots = new long[slots_.length];
        for (int i = 0; i < slots_.length; i++) {
            slots[i] = slots_[i].getSlotID();
        }
        return slots;
    }

    /**
     * to = tomica
     *
     * @tcchtnn hien thu ham goi COpenSession tcchtnn
     * @param id
     * @throws PKCS11Exception
     */
    public static long toCOpenSession(long id) throws PKCS11Exception {
        int index = -1;
        for (int i = 0; i < slots_.length; i++) {
            if (slots_[i].getSlotID() == id) {
                index = i;
                i = slots_.length;
            }
        }
        token_ = slots_[index].getToken();
        session_ = token_.openSession(Token.SessionType.SERIAL_SESSION, Token.SessionReadWriteBehavior.RW_SESSION, null, null);
        return session_.getSessionHandle();
    }

    public static void toCCloseSession(long hSession) throws PKCS11Exception, PKCS11Exception_Tomica_ext {
        to_ext_CheckHSession(hSession);
        session_.closeSession();
    }
    
    /**
     * to = tomica
     *
     * @tcchtnn hien thuc ham goi CLogOut
     * @param sessionHandle
     * @return
     * @throws PKCS11Exception
     * @throws PKCS11Exception_Tomica_ext
     */
    public static long toCLogOut(long sessionHandle) throws PKCS11Exception, PKCS11Exception_Tomica_ext {
        //check sessionhandle is correct
        to_ext_CheckHSession(sessionHandle);
        session_.logout();
        return 1;
    }

    /**
     * to = tomica
     * @param slotID
     * @return
     * @throws PKCS11Exception 
     */
    public static TokenInfo toCGetTokenInfor(long slotID) throws PKCS11Exception {
        Token temp = token_;
        if (token_.getTokenID() != slotID) {
            int index = -1;
            for (int i = 0; i < slots_.length; i++) {
                if (slots_[i].getSlotID() == slotID) {
                    index = i;
                    i = slots_.length;
                }
            }
            temp = slots_[index].getToken();            
        }        
        return temp.getTokenInfo();
    }

    public static void toCFindObjectsInit(long hSession, CK_ATTRIBUTE[] template) throws PKCS11Exception, PKCS11Exception_Tomica_ext{
        to_ext_CheckHSession(hSession);
        modulePKCS11_ = module_.getPKCS11Module();        

        System.out.println("[toCFindObjectsInit] template[0] type: "+ template[0].type);
        System.out.println("[toCFindObjectsInit] template[0] pvalue: "+ template[0].pValue);
        
        ckAttributeSave = new CK_ATTRIBUTE[1];
        ckAttributeSave[0] = new CK_ATTRIBUTE();
        ckAttributeSave[0].type = template[0].type;
        ckAttributeSave[0].pValue = template[0].pValue;

        
        modulePKCS11_.C_FindObjectsInit(session_.getSessionHandle(), ckAttributeSave, true);
//        long[] ObjHandle = modulePKCS11_.C_FindObjects(session_.getSessionHandle(), MAX_OBJS);     
//        if (ObjHandle == null) {
//            System.out.println("[toCFindObjectsInit] cerhandle null");
//        } else {
//            System.out.println("[toCFindObjectsInit] size: "+ObjHandle.length);
//        }
    }
    
    public static long[] toCFindObjects (long hSession, long maxObject ) throws  PKCS11Exception_Tomica_ext, PKCS11Exception{
        to_ext_CheckHSession(hSession);
        //PKCS11 ModuleP11 = module_.getPKCS11Module();
     
        
            modulePKCS11_.C_FindObjectsInit(session_.getSessionHandle(), ckAttributeSave, true);
           long[] cerHandle = modulePKCS11_.C_FindObjects(session_.getSessionHandle(), 16); 
        
       
        return cerHandle;
    }
    
    public static void toCFindObjectsFinal(long hSession) throws PKCS11Exception, PKCS11Exception_Tomica_ext{
        to_ext_CheckHSession(hSession);        
        modulePKCS11_.C_FindObjectsFinal(hSession);
    }
    
    public static void toCLogin(long hSession, char[] pin, long usertype) throws PKCS11Exception, PKCS11Exception_Tomica_ext{
        to_ext_CheckHSession(hSession);
        boolean type = Session.UserType.SO;
        if (usertype >=1) {
            type = Session.UserType.USER;
        }
        session_.login(type, pin);
    }
    
    
    
    public static String loadDll(String name) throws IOException {
        String filename = name;
        if (System.getProperty("sun.arch.data.model").compareTo("32") == 0) {
            name = PATH32 + name + ".dll";
        } else {
            name = PATH64 + name + ".dll";
        }

        InputStream in = ostt1_TokenLib.class.getResourceAsStream(name);

        byte[] buffer = new byte[1024];
        int read = -1;
        File temp = File.createTempFile(filename, ".dll", new File(System.getProperty("java.io.tmpdir")));
        FileOutputStream fos = new FileOutputStream(temp);

        while ((read = in.read(buffer)) != -1) {
            fos.write(buffer, 0, read);
        }
        fos.close();
        in.close();

        return temp.getAbsolutePath();
    }

    public static long connectToken() {

        try {
            slots_ = module_.getSlotList(Module.SlotRequirement.TOKEN_PRESENT);
            token_ = slots_[0].getToken();
            session_ = token_.openSession(Token.SessionType.SERIAL_SESSION, Token.SessionReadWriteBehavior.RW_SESSION, null, null);
        } catch (Exception e) {
            e.printStackTrace();
            return -1;
        }
        return session_.getSessionHandle();
    }

    public static boolean disconnectToken() {
        try {
            session_.closeSession();
            p11finalize();
        } catch (TokenException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public static boolean Login(char[] password) {
        try {
            try {
                session_.logout();
            } catch (Exception e) {
                System.out.println("User hasn't logged in yet");
            }
            session_ = token_.openSession(
                    Token.SessionType.SERIAL_SESSION,
                    Token.SessionReadWriteBehavior.RW_SESSION, null, null);

            char[] pin = password;
            session_.login(Session.UserType.USER, pin);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public static boolean Logout() {
        try {
            session_.logout();
        } catch (TokenException e) {
            e.printStackTrace();
            return false;
        }
        return true;
    }

    public static String GetSerialNumber() {
        String serial = null;
        try {
            TokenInfo info = token_.getTokenInfo();
            serial = info.getSerialNumber();
            return getStringfilter(serial);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return getStringfilter(serial);
    }

    public static boolean ChangeUserPIN(char[] oldpass, char[] newpass) {
        try {
            try {
                session_.logout();
            } catch (Exception e) {
                //System.out.println("User hasn't logged in yet");
            }
            session_ = token_.openSession(Token.SessionType.SERIAL_SESSION,
                    Token.SessionReadWriteBehavior.RW_SESSION, null, null);
            session_.login(Session.UserType.USER, oldpass);
            session_.setPIN(oldpass, newpass);
            return true;
        } catch (PKCS11Exception e) {
            e.printStackTrace();
            return false;
        } catch (TokenException e) {
            e.printStackTrace();
            return false;
        }
    }

    public static boolean ChangeSOPIN(char[] oldpass, char[] newpass) {
        try {
            try {
                session_.logout();
            } catch (Exception e) {
                //System.out.println("User hasn't logged in yet");
            }
            session_ = token_.openSession(Token.SessionType.SERIAL_SESSION,
                    Token.SessionReadWriteBehavior.RW_SESSION, null, null);
            session_.login(Session.UserType.SO, oldpass);
            session_.setPIN(oldpass, newpass);
            return true;
        } catch (PKCS11Exception e) {
            if (e.getErrorCode() == PKCS11Constants.CKR_PIN_INCORRECT) {
                //System.out.println("so pin incorrect");
            }
            e.printStackTrace();
            return false;
        } catch (TokenException e) {
            e.printStackTrace();
            return false;
        }
    }

    public static boolean UnblockPIN(char[] sopin, char[] newpin) {
        try {
            try {
                session_.logout();
            } catch (Exception e) {
                //System.out.println("User hasn't logged in yet");
            }
            session_ = token_.openSession(Token.SessionType.SERIAL_SESSION,
                    Token.SessionReadWriteBehavior.RW_SESSION, null, null);
            session_.login(Session.UserType.SO, sopin);
            session_.initPIN(newpin);
            return true;
        } catch (PKCS11Exception e) {
            if (e.getErrorCode() == PKCS11Constants.CKR_PIN_INCORRECT) {
                //System.out.println("so pin incorrect");
            }
            e.printStackTrace();
            return false;
        } catch (TokenException e) {
            e.printStackTrace();
            return false;
        }
    }

    public static String GetEnumCer(int CerNo, int CerAttr) throws PKCS11Exception {
        PKCS11 ModuleP11 = module_.getPKCS11Module();
        CK_ATTRIBUTE[] findCerAttrList = new CK_ATTRIBUTE[1];
        findCerAttrList[0] = new CK_ATTRIBUTE();
        findCerAttrList[0].type = PKCS11Constants.CKA_CLASS;
        findCerAttrList[0].pValue = new Long(PKCS11Constants.CKO_CERTIFICATE);

        ModuleP11.C_FindObjectsInit(session_.getSessionHandle(), findCerAttrList, true);
        long[] CerHandle = ModuleP11.C_FindObjects(session_.getSessionHandle(), MAX_OBJS);
        ModuleP11.C_FindObjectsFinal(session_.getSessionHandle());

        if (CerHandle == null) {
            return "";
        }

        int num = CerHandle.length;
        if (num <= 0) {
            System.out.println("found: 0 certificate");
            return "";
        } else {
            System.out.println("found: " + num + " certificates");
        }
        long CerHandle_;
        try {
            CerHandle_ = CerHandle[CerNo];
        } catch (Exception e) {
            return "";
        }

        byte[] certValue = null;
        byte[] cerID = null;

        CK_ATTRIBUTE[] getCKAValueAttrList = new CK_ATTRIBUTE[2];
        getCKAValueAttrList[0] = new CK_ATTRIBUTE();
        getCKAValueAttrList[0].type = PKCS11Constants.CKA_VALUE;
        getCKAValueAttrList[1] = new CK_ATTRIBUTE();
        getCKAValueAttrList[1].type = PKCS11Constants.CKA_ID;

        ModuleP11.C_GetAttributeValue(session_.getSessionHandle(), CerHandle_, getCKAValueAttrList, true);

        certValue = (byte[]) getCKAValueAttrList[0].pValue;
        cerID = (byte[]) getCKAValueAttrList[1].pValue;

        String strCerID = "";
        try {
            strCerID = new String(cerID, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }


        if (CerAttr == 1) {
            return DatatypeConverter.printHexBinary(certValue);
        } else {
            return getStringfilter(strCerID);
        }
    }

    public static String[] GetCertificateID() throws PKCS11Exception {

        PKCS11 ModuleP11 = module_.getPKCS11Module();
        CK_ATTRIBUTE[] findCerAttrList = new CK_ATTRIBUTE[1];
        findCerAttrList[0] = new CK_ATTRIBUTE();
        findCerAttrList[0].type = PKCS11Constants.CKA_CLASS;
        findCerAttrList[0].pValue = new Long(PKCS11Constants.CKO_CERTIFICATE);

        ModuleP11.C_FindObjectsInit(session_.getSessionHandle(), findCerAttrList, true);
        long[] CerHandle = ModuleP11.C_FindObjects(session_.getSessionHandle(), MAX_OBJS);
        ModuleP11.C_FindObjectsFinal(session_.getSessionHandle());

        if (CerHandle == null) {
            return null;
        }

        int num = CerHandle.length;
        if (num <= 0) {
            System.out.println("found: 0 certificate");
            return null;
        } else {
            System.out.println("found: " + num + " certificates");
        }

        byte[] cerID = null;
        String strCerID = "";

        CK_ATTRIBUTE[] getCKAValueAttrList = new CK_ATTRIBUTE[1];
        getCKAValueAttrList[0] = new CK_ATTRIBUTE();
        getCKAValueAttrList[0].type = PKCS11Constants.CKA_ID;

        String Result[] = new String[CerHandle.length];

        for (int i = 0; i < CerHandle.length; i++) {
            ModuleP11.C_GetAttributeValue(session_.getSessionHandle(), CerHandle[i], getCKAValueAttrList, true);
            cerID = (byte[]) getCKAValueAttrList[0].pValue;

            try {
                strCerID = new String(cerID, "UTF-8");
                Result[i] = getStringfilter(strCerID);
                System.out.println(DatatypeConverter.printHexBinary(cerID));
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }

        return Result;
    }

    public static String GetEnumPub(int CerNo) throws PKCS11Exception {
        PKCS11 ModuleP11 = module_.getPKCS11Module();
        CK_ATTRIBUTE[] findObjAttrList = new CK_ATTRIBUTE[1];
        findObjAttrList[0] = new CK_ATTRIBUTE();
        findObjAttrList[0].type = PKCS11Constants.CKA_CLASS;
        findObjAttrList[0].pValue = new Long(PKCS11Constants.CKO_PUBLIC_KEY);

        ModuleP11.C_FindObjectsInit(session_.getSessionHandle(), findObjAttrList, true);
        long[] ObjHandle = ModuleP11.C_FindObjects(session_.getSessionHandle(), MAX_OBJS);
        ModuleP11.C_FindObjectsFinal(session_.getSessionHandle());

        if (ObjHandle == null) {
            return "";
        }

        int num = ObjHandle.length;
        if (num <= 0) {
            System.out.println("found: 0 publickey");
            return "";
        } else {
            System.out.println("found: " + num + " publickey");
        }
        long ObjHandle_;
        try {
            ObjHandle_ = ObjHandle[CerNo];
        } catch (Exception e) {
            return "";
        }
        byte[] objID = null;

        CK_ATTRIBUTE[] getAttrList = new CK_ATTRIBUTE[1];
        getAttrList[0] = new CK_ATTRIBUTE();
        getAttrList[0].type = PKCS11Constants.CKA_ID;

        ModuleP11.C_GetAttributeValue(session_.getSessionHandle(), ObjHandle_, getAttrList, true);

        objID = (byte[]) getAttrList[0].pValue;

        String strObjID = "";
        try {
            strObjID = new String(objID, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return getStringfilter(strObjID);
    }

    
    public static void testGetPri() throws PKCS11Exception {
        PKCS11 ModuleP11 = module_.getPKCS11Module();
        CK_ATTRIBUTE[] findObjAttrList = new CK_ATTRIBUTE[1];
        findObjAttrList[0] = new CK_ATTRIBUTE();
        findObjAttrList[0].type = PKCS11Constants.CKA_CLASS;
        findObjAttrList[0].pValue = new Long(PKCS11Constants.CKO_PUBLIC_KEY);

        ModuleP11.C_FindObjectsInit(session_.getSessionHandle(), findObjAttrList, true);
        long[] ObjHandle = ModuleP11.C_FindObjects(session_.getSessionHandle(), MAX_OBJS);      

        if (ObjHandle == null) {

        }

        int num = ObjHandle.length;
        if (num <= 0) {
            System.out.println("found: 0 publickey");
           
        } else {
            System.out.println("found: " + num + " publickey");
        }
        ModuleP11.C_FindObjectsFinal(session_.getSessionHandle());
    }
    
    public static String GetEnumPri(int CerNo) throws TokenException {
        PKCS11 ModuleP11 = module_.getPKCS11Module();
        CK_ATTRIBUTE[] findObjAttrList = new CK_ATTRIBUTE[1];
        findObjAttrList[0] = new CK_ATTRIBUTE();
        findObjAttrList[0].type = PKCS11Constants.CKA_CLASS;
        findObjAttrList[0].pValue = new Long(PKCS11Constants.CKO_PRIVATE_KEY);

        ModuleP11.C_FindObjectsInit(session_.getSessionHandle(), findObjAttrList, true);
        long[] ObjHandle = ModuleP11.C_FindObjects(session_.getSessionHandle(), MAX_OBJS);
        ModuleP11.C_FindObjectsFinal(session_.getSessionHandle());

        if (ObjHandle == null) {
            return "";
        }

        int num = ObjHandle.length;
        if (num <= 0) {
            System.out.println("found: 0 privatekey");
            return "";
        } else {
            System.out.println("found: " + num + " privatekey");
        }
        long ObjHandle_;
        try {
            ObjHandle_ = ObjHandle[CerNo];
        } catch (Exception e) {
            return "";
        }
        byte[] objID = null;

        CK_ATTRIBUTE[] getAttrList = new CK_ATTRIBUTE[1];
        getAttrList[0] = new CK_ATTRIBUTE();
        getAttrList[0].type = PKCS11Constants.CKA_ID;

        ModuleP11.C_GetAttributeValue(session_.getSessionHandle(), ObjHandle_, getAttrList, true);

        objID = (byte[]) getAttrList[0].pValue;

        String strObjID = "";
        try {
            strObjID = new String(objID, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        return getStringfilter(strObjID);
    }

    public static byte[] encryptData(String plaintext, RSAPublicKey publicKey) {
        if (null == plaintext) {
            return null;
        }
        byte[] data;
        byte[] cipher_ = null;
        Mechanism signatureMechanism = Mechanism.get(PKCS11Constants.CKM_RSA_PKCS);

        try {
            data = plaintext.getBytes("UTF-8");
            session_.encryptInit(signatureMechanism, publicKey);
            cipher_ = session_.encrypt(data);
        } catch (UnsupportedEncodingException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        } catch (TokenException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            return null;
        }

        return cipher_;
    }

    public static byte[] decryptData(byte[] cipher_, RSAPrivateKey privateKey) {
        byte[] plain = null;
        if (null == cipher_) {
            return null;
        }
        Mechanism signatureMechanism = Mechanism.get(PKCS11Constants.CKM_RSA_PKCS);
        try {
            session_.decryptInit(signatureMechanism, privateKey);
            plain = session_.decrypt(cipher_);
        } catch (TokenException e) {
            return null;
        }
        return plain;
    }

    public static boolean isDefaultPIN() {
        TokenInfo info = null;
        try {
            info = token_.getTokenInfo();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return info.isUserPinToBeChanged();
    }

    public static X509Certificate getX509CertificateObject(int CerNo) {
        try {
            PKCS11 ModuleP11 = module_.getPKCS11Module();
            CK_ATTRIBUTE[] findCerAttrList = new CK_ATTRIBUTE[1];
            findCerAttrList[0] = new CK_ATTRIBUTE();
            findCerAttrList[0].type = PKCS11Constants.CKA_CLASS;
            findCerAttrList[0].pValue = new Long(PKCS11Constants.CKO_CERTIFICATE);

            ModuleP11.C_FindObjectsInit(session_.getSessionHandle(), findCerAttrList, true);
            long[] CerHandle = ModuleP11.C_FindObjects(session_.getSessionHandle(), MAX_OBJS);
            ModuleP11.C_FindObjectsFinal(session_.getSessionHandle());

            if (CerHandle == null) {
                return null;
            }

            int num = CerHandle.length;
            if (num <= 0) {
                System.out.println("found: 0 certificate");
                return null;
            } else {
                System.out.println("found: " + num + " certificates");
            }
            long CerHandle_;
            try {
                CerHandle_ = CerHandle[CerNo];
            } catch (Exception e) {
                return null;
            }

            byte[] certValue = null;

            CK_ATTRIBUTE[] getCKAValueAttrList = new CK_ATTRIBUTE[1];
            getCKAValueAttrList[0] = new CK_ATTRIBUTE();
            getCKAValueAttrList[0].type = PKCS11Constants.CKA_VALUE;

            ModuleP11.C_GetAttributeValue(session_.getSessionHandle(), CerHandle_, getCKAValueAttrList, true);

            certValue = (byte[]) getCKAValueAttrList[0].pValue;

            X509Certificate x509cer = null;

            InputStream inStream = new ByteArrayInputStream(certValue);
            CertificateFactory cf;
            try {
                cf = CertificateFactory.getInstance("X.509");
                x509cer = (X509Certificate) cf.generateCertificate(inStream);
            } catch (java.security.cert.CertificateException e) {
                e.printStackTrace();
            }

            return x509cer;
        } catch (PKCS11Exception e) {
            e.printStackTrace();
            return null;
        }

    }

    public static String getIssuerDN(X509Certificate x509) {
        return x509.getIssuerDN().getName();
    }

    public static String getSubjectDN(X509Certificate x509) {
        return x509.getSubjectDN().getName();
    }

    public static String getDateValid(X509Certificate x509) {
        SimpleDateFormat df = new SimpleDateFormat("MMMM, dd, yyyy hh:mm:ss a");
        String datevalid = df.format(x509.getNotBefore());
        return datevalid;
    }

    public static String getDateExpired(X509Certificate x509) {
        SimpleDateFormat df = new SimpleDateFormat("MMMM, dd, yyyy hh:mm:ss a");
        String dateexpired = df.format(x509.getNotAfter());
        return dateexpired;
    }

    public static String getSerialNumber(X509Certificate x509) {
        return DatatypeConverter.printHexBinary(x509.getSerialNumber().toByteArray());
    }

    public static String getSigAlgName(X509Certificate x509) {
        return x509.getSigAlgName();
    }

    public static int getVersion(X509Certificate x509) {
        return x509.getVersion();
    }

    public static String getSigAlgOID(X509Certificate x509) {
        return x509.getSigAlgOID();
    }

    public static int getKeySize(X509Certificate x509) {
        RSAKey rsaKey = (RSAKey) (x509.getPublicKey());
        int keySize = rsaKey.getModulus().bitLength();
        return keySize;
    }

    public static boolean[] getKeyUsage(X509Certificate x509) {
        boolean[] keyUsage = x509.getKeyUsage();
        return keyUsage;
    }

    public static boolean p11finalize() throws PKCS11Exception {
        module_.finalize(null);
        return true;
    }

    public static byte[] signpkcs7(String datatobesign, int CerNo, RSAPrivateKey privateKey) throws TokenException, GeneralSecurityException, IOException, Exception {
        X509Certificate pCertContext = getX509CertificateObject(CerNo);
        byte[] temp_cer = pCertContext.getEncoded();
        byte[] serial_cer = pCertContext.getSerialNumber().toByteArray();

        //hash data
        byte[] data_sign = datatobesign.getBytes("UTF-8");
        MessageDigest cript = MessageDigest.getInstance("SHA-1");
        cript.reset();
        cript.update(data_sign);
        byte[] pbHash = cript.digest();

        if (pbHash == null) {
            return "Error: no cert or invalid cert".getBytes("UTF-8");
        }

        //building ASN.1
        tlvINT I0 = new tlvINT();
        I0.data = new byte[1];
        I0.len = 1;

        tlvOID OID1 = new tlvOID();
        byte[] pbOID1 = {(byte) 0x2B, (byte) 0x0E, (byte) 0x03, (byte) 0x02, (byte) 0x1A};
        OID1.load(pbOID1, 5, 0);
        tlvNULL null0 = new tlvNULL();
        tlvSEshort SE2 = new tlvSEshort();
        SE2.add(OID1);
        SE2.add(null0);

        tlvSET SET0 = new tlvSET();
        SET0.add(SE2);

        tlvOID OID2 = new tlvOID();
        byte[] pbOID2 = {(byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x07, (byte) 0x01};
        OID2.load(pbOID2, 9, 0);

        tlvOctetStringLong Octet0 = new tlvOctetStringLong();
        Octet0.load(data_sign, data_sign.length, 0);
        tlvZeroLong zero1 = new tlvZeroLong();
        zero1.add(Octet0);

        tlvSElong SE3 = new tlvSElong();
        SE3.add(OID2);
        SE3.add(zero1);

        tlv_long zeroCert = new tlv_long();
        zeroCert.tag = (short) 0xA082;

        zeroCert.load(temp_cer, temp_cer.length, 0);

        tlvINT I_before_issuer = new tlvINT();
        I_before_issuer.data = new byte[1];
        I_before_issuer.len = 1;

        //IssuerINT
        tlvSEshort SEIssuer = new tlvSEshort();
        int pos;

        byte[] pbOIDCountryName = {(byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x06};
        byte[] temp1 = new byte[3];
        System.arraycopy(pbOIDCountryName, 2, temp1, 0, 3);
        tlvOID OIDCountryName = new tlvOID();
        OIDCountryName.load(temp1, 3, 0);
        tlvSEshort SECountryName = new tlvSEshort();
        SECountryName.add(OIDCountryName);
        //pos = searchByteArray(pCertContext->pbCertEncoded, pCertContext->cbCertEncoded, pbOIDCountryName, 5);

        pos = searchByteArray(temp_cer, temp_cer.length, pbOIDCountryName, 5);
        if (pos > -1) {
            //SECountryName.add(pCertContext->pbCertEncoded+pos+5, *(pCertContext->pbCertEncoded+pos+6)+2);
            SECountryName.add(temp_cer, temp_cer[pos + 6] + 2, pos + 5);
            tlvSET SETCountryName = new tlvSET();
            SETCountryName.add(SECountryName);
            SEIssuer.add(SETCountryName);
        }

        byte[] pbOIDOrgName = {(byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0A};
        tlvOID OIDOrgName = new tlvOID();
        OIDOrgName.load(pbOIDOrgName, 3, 2);
        tlvSEshort SEOrgName = new tlvSEshort();
        SEOrgName.add(OIDOrgName);
        pos = searchByteArray(temp_cer, temp_cer.length, pbOIDOrgName, 5);
        if (pos > -1) {
            //SEOrgName.add(pCertContext->pbCertEncoded+pos+5, *(pCertContext->pbCertEncoded+pos+6)+2);
            SEOrgName.add(temp_cer, temp_cer[pos + 6] + 2, pos + 5);
            tlvSET SETOrgName = new tlvSET();
            SETOrgName.add(SEOrgName);
            SEIssuer.add(SETOrgName);
        }

        byte[] pbOIDOrgUnitName = {(byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x0B};
        tlvOID OIDOrgUnitName = new tlvOID();
        OIDOrgUnitName.load(pbOIDOrgUnitName, 3, 2);
        tlvSEshort SEOrgUnitName = new tlvSEshort();
        SEOrgUnitName.add(OIDOrgUnitName);
        pos = searchByteArray(temp_cer, temp_cer.length, pbOIDOrgUnitName, 5);
        if (pos > -1) {
            SEOrgUnitName.add(temp_cer, temp_cer[pos + 6] + 2, pos + 5);
            tlvSET SETOrgUnitName = new tlvSET();
            SETOrgUnitName.add(SEOrgUnitName);
            SEIssuer.add(SETOrgUnitName);
        }

        byte[] pbOIDCommonName = {(byte) 0x06, (byte) 0x03, (byte) 0x55, (byte) 0x04, (byte) 0x03};
        tlvOID OIDCommonName = new tlvOID();
        OIDCommonName.load(pbOIDCommonName, 3, 2);
        tlvSEshort SECommonName = new tlvSEshort();
        SECommonName.add(OIDCommonName);
        pos = searchByteArray(temp_cer, temp_cer.length, pbOIDCommonName, 5);
        if (pos > -1) {
            SECommonName.add(temp_cer, temp_cer[pos + 6] + 2, pos + 5);
            tlvSET SETCommonName = new tlvSET();
            SETCommonName.add(SECommonName);
            SEIssuer.add(SETCommonName);
        } else {
            return "Error: no cert or invalid cert".getBytes("UTF-8");//cert ko có CommonName là invalid
        }

        tlvINT INTIssuer = new tlvINT();
        //INTIssuer.load(pbINTIssuer,(pCertContext->pCertInfo->SerialNumber.cbData));
        INTIssuer.load(serial_cer, serial_cer.length, 0);

        tlvSEshort SEIssuerINT = new tlvSEshort();
        SEIssuerINT.add(SEIssuer);
        SEIssuerINT.add(INTIssuer);
        //End of IssuerINT

        //sha1OID
        byte[] baOIDsha1 = {(byte) 0x2B, (byte) 0x0E, (byte) 0x03, (byte) 0x02, (byte) 0x1A};
        tlvOID OIDsha1 = new tlvOID();
        OIDsha1.load(baOIDsha1, 5, 0);
        tlvNULL null1 = new tlvNULL();
        tlvSEshort SEsha1 = new tlvSEshort();
        SEsha1.add(OIDsha1);
        SEsha1.add(null1);
        //End of sha1OID

        byte[] baOIDContentType = {(byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x09, (byte) 0x03};
        tlvOID OIDContentType = new tlvOID();
        OIDContentType.load(baOIDContentType, 9, 0);
        byte[] baOIDPkcs7data = {(byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x07, (byte) 0x01};
        tlvOID OIDPkcs7data = new tlvOID();
        OIDPkcs7data.load(baOIDPkcs7data, 9, 0);
        tlvSET SETPkcs7data = new tlvSET();
        SETPkcs7data.add(OIDPkcs7data);
        tlvSEshort SEContentType = new tlvSEshort();
        SEContentType.add(OIDContentType);
        SEContentType.add(SETPkcs7data);

        byte[] baOIDSigningTime = {(byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x09, (byte) 0x05};
        tlvOID OIDSigningTime = new tlvOID();
        OIDSigningTime.load(baOIDSigningTime, 9, 0);

        Calendar calendar = Calendar.getInstance();
        Date d = new Date();
        calendar.setTime(d);
        int year = calendar.get(Calendar.YEAR);
        int month = calendar.get(Calendar.MONTH) + 1;
        int date = calendar.get(Calendar.DATE);
        int hour = calendar.get(Calendar.HOUR_OF_DAY);
        int min = calendar.get(Calendar.MINUTE);
        int sec = calendar.get(Calendar.SECOND);


        byte[] baSigningTime = new byte[13];
        baSigningTime[0] = (byte) ((year % 100) / 10 + '0');
        baSigningTime[1] = (byte) ((year % 100) % 10 + '0');
        baSigningTime[2] = (byte) (month / 10 + '0');
        baSigningTime[3] = (byte) (month % 10 + '0');
        baSigningTime[4] = (byte) (date / 10 + '0');
        baSigningTime[5] = (byte) (date % 10 + '0');
        baSigningTime[6] = (byte) (hour / 10 + '0');
        baSigningTime[7] = (byte) (hour % 10 + '0');
        baSigningTime[8] = (byte) (min / 10 + '0');
        baSigningTime[9] = (byte) (min % 10 + '0');
        baSigningTime[10] = (byte) (sec / 10 + '0');
        baSigningTime[11] = (byte) (sec % 10 + '0');
        baSigningTime[12] = 'Z';

        //byte baSigningTime[] = {0x31, 0x31, 0x30, 0x38, 0x30, 0x31, 0x30, 0x39, 0x30, 0x31, 0x32, 0x30, 0x5A};
        tlvUTCTime UTCSigningTime = new tlvUTCTime();
        UTCSigningTime.load(baSigningTime, 13, 0);
        tlvSET SETSigningTime = new tlvSET();
        SETSigningTime.add(UTCSigningTime);

        tlvSEshort SESigningTime = new tlvSEshort();
        SESigningTime.add(OIDSigningTime);
        SESigningTime.add(SETSigningTime);

        byte[] baOIDMsgDigest = {(byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x09, (byte) 0x04};

        tlvOID OIDMsgDigest = new tlvOID();
        OIDMsgDigest.load(baOIDMsgDigest, 9, 0);

        tlvOctetString OctetMsgDigest = new tlvOctetString();
        OctetMsgDigest.load(pbHash, 20, 0);

        tlvSET SETMsgDigest = new tlvSET();
        SETMsgDigest.add(OctetMsgDigest);

        tlvSEshort SEMsgDigest = new tlvSEshort();
        SEMsgDigest.add(OIDMsgDigest);
        SEMsgDigest.add(SETMsgDigest);

        tlvZero zeroSignInfo = new tlvZero();
        zeroSignInfo.add(SEContentType);
        zeroSignInfo.add(SESigningTime);
        zeroSignInfo.add(SEMsgDigest);

        byte[] baOIDRsa = {(byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x01, (byte) 0x01};
        tlvOID OIDRsa = new tlvOID();
        OIDRsa.load(baOIDRsa, 9, 0);
        tlvSEshort SERsa = new tlvSEshort();
        SERsa.add(OIDRsa);
        SERsa.add(null1);

        //sign pkcs#1
        byte[] pbSignature = null;



        byte[] temp_zeroSignInfo = zeroSignInfo.getByte();
        int zeroSigninfo_length = zeroSignInfo.len;

        byte[] temp_sign = new byte[zeroSigninfo_length + 2];
        System.arraycopy(temp_zeroSignInfo, 0, temp_sign, 0, zeroSigninfo_length + 2);
        temp_sign[0] = (byte) 0x31;

        //pbSignature=signData(temp_sign, privateKey);
        pbSignature = signDataPKCS1(temp_sign, privateKey);

        int dwSigLen = pbSignature.length;

        //add to ASN.1
        tlvOctetString81 OctetRSASignature = new tlvOctetString81();
        OctetRSASignature.load(pbSignature, dwSigLen, 0);

        tlvSElong SEPkcs7Signature = new tlvSElong();
        SEPkcs7Signature.add(I_before_issuer);
        SEPkcs7Signature.add(SEIssuerINT);
        SEPkcs7Signature.add(SEsha1);
        SEPkcs7Signature.add(zeroSignInfo);
        SEPkcs7Signature.add(SERsa);
        SEPkcs7Signature.add(OctetRSASignature);

        tlvSETlong SETPkcs7Signature = new tlvSETlong();
        SETPkcs7Signature.add(SEPkcs7Signature);

        tlvSElong SESignedData = new tlvSElong();
        SESignedData.add(I0);
        SESignedData.add(SET0);
        SESignedData.add(SE3);
        SESignedData.add(zeroCert);
        SESignedData.add(SETPkcs7Signature);

        tlvZeroLong zeroSignedData = new tlvZeroLong();
        zeroSignedData.add(SESignedData);

        byte[] baOIDSignedData = {(byte) 0x2A, (byte) 0x86, (byte) 0x48, (byte) 0x86, (byte) 0xF7, (byte) 0x0D, (byte) 0x01, (byte) 0x07, (byte) 0x02};
        tlvOID OIDSignedData = new tlvOID();
        OIDSignedData.load(baOIDSignedData, 9, 0);
        tlvSElong SERoot = new tlvSElong();
        SERoot.add(OIDSignedData);
        SERoot.add(zeroSignedData);

        Logout();
        return SERoot.getByte();
    }

    private static int searchByteArray(byte[] str, int str_len, byte[] subStr, int subStr_len) {
        for (int i = 0; i < str_len - subStr_len; i++) {
            int j;
            for (j = 0; j < subStr_len; j++) {
                if (str[i + j] != subStr[j] && subStr[j] != '*') {
                    break;
                }
            }
            if (j == subStr_len) {
                return i;
            }
        }
        return -1;
    }

    public static RSAPrivateKey getPrivateKeyPair(int CerNo) throws GeneralSecurityException, IOException, TokenException {
        //get private key
        RSAPrivateKey templateSignatureKey = new RSAPrivateKey();
        RSAPrivateKey temp_key = null;
        templateSignatureKey.getSign().setBooleanValue(Boolean.TRUE);

        session_.findObjectsInit(templateSignatureKey);

        Object[] temp_rsaprivatekey = session_.findObjects(MAX_OBJS);


        if (temp_rsaprivatekey.length > 0) {
            if (CerNo > (temp_rsaprivatekey.length - 1)) {
                return null;
            }
            temp_key = (RSAPrivateKey) temp_rsaprivatekey[CerNo];
        }
        session_.findObjectsFinal();
        return temp_key;
    }

    public static RSAPublicKey getPublicKeyPair(int CerNo) throws GeneralSecurityException, IOException, TokenException {
        RSAPublicKey templateSignatureKey = new RSAPublicKey();
        RSAPublicKey temp_key = null;
        templateSignatureKey.getVerify().setBooleanValue(Boolean.TRUE);

        session_.findObjectsInit(templateSignatureKey);

        Object[] temp_rsapublickey = session_.findObjects(MAX_OBJS);


        if (temp_rsapublickey.length > 0) {
            if (CerNo > (temp_rsapublickey.length - 1)) {
                return null;
            }
            temp_key = (RSAPublicKey) temp_rsapublickey[CerNo];
        }
        session_.findObjectsFinal();
        return temp_key;
    }

    public static byte[] signDataPKCS1(byte[] dataToBeSigned, RSAPrivateKey privateKey) {
        byte[] signatureValue = null;
        Mechanism signatureMechanism = Mechanism.get(PKCS11Constants.CKM_SHA1_RSA_PKCS);

        try {
            session_.signInit(signatureMechanism, privateKey);
            signatureValue = session_.sign(dataToBeSigned);
        } catch (TokenException e) {
            e.printStackTrace();
        }
        return signatureValue;
    }

    public static boolean verifySignPKCS1(byte[] data, byte[] signature, RSAPublicKey publicKey) {
        Mechanism signatureMechanism = Mechanism.get(PKCS11Constants.CKM_SHA1_RSA_PKCS);
        try {
            session_.verifyInit(signatureMechanism, publicKey);
            session_.verify(data, signature);
        } catch (TokenException e) {
            return false;
        }
        return true;
    }
    /*	
     public static String VerifyPKCS7Signature(String signData, byte[] signature)
     {
     AccessController.doPrivileged(new PrivilegedAction() {
     public Object run() {
     Security.addProvider(new BouncyCastleProvider());
     return null;
     }
     });
        
     boolean verified = false;
     CMSProcessableByteArray cmsByteArray;

     try {
     cmsByteArray = new CMSProcessableByteArray(signData.getBytes("UTF-8"));
     CMSSignedData sp = new CMSSignedData(cmsByteArray, signature);

     Store                   certStore = sp.getCertificates();
     SignerInformationStore  signers = sp.getSignerInfos();
	        
     Collection<?>              c = signers.getSigners();
     Iterator<?>                it = c.iterator();
	       
     while (it.hasNext())
     {
     SignerInformation   signer = (SignerInformation)it.next();
     Collection<?>          certCollection = certStore.getMatches(signer.getSID());

     Iterator<?>        certIt = certCollection.iterator();
     X509CertificateHolder cert = (X509CertificateHolder)certIt.next();
     verified = signer.verify(new JcaSimpleSignerInfoVerifierBuilder().setProvider("BC").build(cert));
     }
     } catch (UnsupportedEncodingException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
     return e.toString();
     } catch (CMSException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
     return e.toString();
     } catch (OperatorCreationException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
     return e.toString();
     } catch (CertificateException e) {
     // TODO Auto-generated catch block
     e.printStackTrace();
     return e.toString();
     }

     if(verified)
     return "1";
     return "0";
     }
     */

    public static String genKeyPair(int bitsize) throws TokenException, NoSuchAlgorithmException, InvalidKeySpecException {
        HashSet supportedMechanisms = new HashSet(Arrays.asList(token_.getMechanismList()));
        MechanismInfo signatureMechanismInfo;
        if (supportedMechanisms.contains(Mechanism.get(PKCS11Constants.CKM_RSA_PKCS))) {
            signatureMechanismInfo = token_.getMechanismInfo(Mechanism
                    .get(PKCS11Constants.CKM_RSA_PKCS));
        } else if (supportedMechanisms.contains(Mechanism.get(PKCS11Constants.CKM_RSA_X_509))) {
            signatureMechanismInfo = token_.getMechanismInfo(Mechanism
                    .get(PKCS11Constants.CKM_RSA_X_509));
        } else if (supportedMechanisms.contains(Mechanism.get(PKCS11Constants.CKM_RSA_9796))) {
            signatureMechanismInfo = token_.getMechanismInfo(Mechanism
                    .get(PKCS11Constants.CKM_RSA_9796));
        } else if (supportedMechanisms.contains(Mechanism
                .get(PKCS11Constants.CKM_RSA_PKCS_OAEP))) {
            signatureMechanismInfo = token_.getMechanismInfo(Mechanism
                    .get(PKCS11Constants.CKM_RSA_PKCS_OAEP));
        } else {
            signatureMechanismInfo = null;
        }

        Mechanism keyPairGenerationMechanism = Mechanism
                .get(PKCS11Constants.CKM_RSA_PKCS_KEY_PAIR_GEN);
        RSAPublicKey rsaPublicKeyTemplate = new RSAPublicKey();
        RSAPrivateKey rsaPrivateKeyTemplate = new RSAPrivateKey();

        // set the general attributes for the public key
        rsaPublicKeyTemplate.getModulusBits().setLongValue(new Long(bitsize));
        byte[] publicExponentBytes = {0x01, 0x00, 0x01}; // 2^16 + 1
        rsaPublicKeyTemplate.getPublicExponent().setByteArrayValue(publicExponentBytes);
        rsaPublicKeyTemplate.getToken().setBooleanValue(Boolean.TRUE);
        byte[] id = new byte[20];
        new Random().nextBytes(id);
        rsaPublicKeyTemplate.getId().setByteArrayValue(id);
        //rsaPublicKeyTemplate.getLabel().setCharArrayValue(args[2].toCharArray());

        rsaPrivateKeyTemplate.getSensitive().setBooleanValue(Boolean.TRUE);
        rsaPrivateKeyTemplate.getToken().setBooleanValue(Boolean.TRUE);
        rsaPrivateKeyTemplate.getPrivate().setBooleanValue(Boolean.TRUE);
        rsaPrivateKeyTemplate.getId().setByteArrayValue(id);
        //byte[] subject = args[1].getBytes();
        //rsaPrivateKeyTemplate.getSubject().setByteArrayValue(subject);
        //rsaPrivateKeyTemplate.getLabel().setCharArrayValue(args[2].toCharArray());

        // set the attributes in a way netscape does, this should work with most tokens
        if (signatureMechanismInfo != null) {
            rsaPublicKeyTemplate.getVerify().setBooleanValue(
                    new Boolean(signatureMechanismInfo.isVerify()));
            rsaPublicKeyTemplate.getVerifyRecover().setBooleanValue(
                    new Boolean(signatureMechanismInfo.isVerifyRecover()));
            rsaPublicKeyTemplate.getEncrypt().setBooleanValue(
                    new Boolean(signatureMechanismInfo.isEncrypt()));
            rsaPublicKeyTemplate.getDerive().setBooleanValue(
                    new Boolean(signatureMechanismInfo.isDerive()));
            rsaPublicKeyTemplate.getWrap().setBooleanValue(
                    new Boolean(signatureMechanismInfo.isWrap()));

            rsaPrivateKeyTemplate.getSign().setBooleanValue(
                    new Boolean(signatureMechanismInfo.isSign()));
            rsaPrivateKeyTemplate.getSignRecover().setBooleanValue(
                    new Boolean(signatureMechanismInfo.isSignRecover()));
            rsaPrivateKeyTemplate.getDecrypt().setBooleanValue(
                    new Boolean(signatureMechanismInfo.isDecrypt()));
            rsaPrivateKeyTemplate.getDerive().setBooleanValue(
                    new Boolean(signatureMechanismInfo.isDerive()));
            rsaPrivateKeyTemplate.getUnwrap().setBooleanValue(
                    new Boolean(signatureMechanismInfo.isUnwrap()));
        } else {
            // if we have no information we assume these attributes
            rsaPrivateKeyTemplate.getSign().setBooleanValue(Boolean.TRUE);
            rsaPrivateKeyTemplate.getDecrypt().setBooleanValue(Boolean.TRUE);

            rsaPublicKeyTemplate.getVerify().setBooleanValue(Boolean.TRUE);
            rsaPublicKeyTemplate.getEncrypt().setBooleanValue(Boolean.TRUE);
        }

        // netscape does not set these attribute, so we do no either
        rsaPublicKeyTemplate.getKeyType().setPresent(false);
        rsaPublicKeyTemplate.getObjectClass().setPresent(false);

        rsaPrivateKeyTemplate.getKeyType().setPresent(false);
        rsaPrivateKeyTemplate.getObjectClass().setPresent(false);

        KeyPair generatedKeyPair = session_.generateKeyPair(keyPairGenerationMechanism,
                rsaPublicKeyTemplate, rsaPrivateKeyTemplate);
        RSAPublicKey generatedRSAPublicKey = (RSAPublicKey) generatedKeyPair.getPublicKey();
        RSAPrivateKey generatedRSAPrivateKey = (RSAPrivateKey) generatedKeyPair.getPrivateKey();

        String ID = DatatypeConverter.printHexBinary(id);
        System.out.println("ID: " + ID);
        Long _handle = new Long(getObjectHandlePrivateKeyByID(ID));
        String container = getContainerByObjectHandle(_handle);

        //System.out.println("Container name: "+ container);

        return ID;
    }

    public static RSAPrivateKey getPrivateKeyByID(String KeyID) {
        try {
            RSAPrivateKey templateSignatureKey = new RSAPrivateKey();
            templateSignatureKey.getSign().setBooleanValue(Boolean.TRUE);

            session_.findObjectsInit(templateSignatureKey);

            Object[] temp_rsaprivatekey = session_.findObjects(MAX_OBJS);


            if (temp_rsaprivatekey.length > 0) {
                int i = 0;
                while (i < temp_rsaprivatekey.length) {
                    RSAPrivateKey temp_key = (RSAPrivateKey) temp_rsaprivatekey[i];
                    String _keyid = DatatypeConverter.printHexBinary(temp_key.getId().getByteArrayValue());
                    System.out.println(_keyid);
                    if (KeyID.compareTo(_keyid) == 0) {
                        return temp_key;
                    }
                    i++;
                }
            } else {
                System.out.println("no private key found");
            }
            session_.findObjectsFinal();
        } catch (TokenException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static RSAPublicKey getPublicKeyByID(String KeyID) {
        try {
            RSAPublicKey templateSignatureKey = new RSAPublicKey();
            templateSignatureKey.getVerify().setBooleanValue(Boolean.TRUE);

            session_.findObjectsInit(templateSignatureKey);

            Object[] temp_rsapublickey = session_.findObjects(MAX_OBJS);


            if (temp_rsapublickey.length > 0) {
                int i = 0;
                while (i < temp_rsapublickey.length) {
                    RSAPublicKey temp_key = (RSAPublicKey) temp_rsapublickey[i];
                    String _keyid = DatatypeConverter.printHexBinary(temp_key.getId().getByteArrayValue());
                    System.out.println(_keyid);
                    if (KeyID.compareTo(_keyid) == 0) {
                        return temp_key;
                    }
                    i++;
                }
            } else {
                System.out.println("no public key found");
            }
            session_.findObjectsFinal();
        } catch (TokenException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String getObjectHandlePrivateKeyByID(String KeyID) {
        try {
            RSAPrivateKey templateSignatureKey = new RSAPrivateKey();
            templateSignatureKey.getSign().setBooleanValue(Boolean.TRUE);

            session_.findObjectsInit(templateSignatureKey);

            Object[] temp_rsaprivatekey = session_.findObjects(MAX_OBJS);


            if (temp_rsaprivatekey.length > 0) {
                int i = 0;
                while (i < temp_rsaprivatekey.length) {
                    RSAPrivateKey temp_key = (RSAPrivateKey) temp_rsaprivatekey[i];
                    String _keyid = DatatypeConverter.printHexBinary(temp_key.getId().getByteArrayValue());

                    if (KeyID.compareTo(_keyid) == 0) {
                        System.out.println("object handle: " + temp_rsaprivatekey[i].getObjectHandle());
                        return String.valueOf(temp_rsaprivatekey[i].getObjectHandle());
                        //return temp_key;
                    }
                    i++;
                }
            } else {
                System.out.println("no private key found");
            }
            session_.findObjectsFinal();
        } catch (TokenException e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String getContainerByObjectHandle(long obHandle) {
        try {
            String ID = null;
            PKCS11 ModuleP11 = module_.getPKCS11Module();

            byte[] cerID = null;

            CK_ATTRIBUTE[] getCKAValueAttrList = new CK_ATTRIBUTE[1];
            getCKAValueAttrList[0] = new CK_ATTRIBUTE();
            getCKAValueAttrList[0].type = PKCS11Constants.CKA_CONTAINER_NAME;

            ModuleP11.C_GetAttributeValue(session_.getSessionHandle(), obHandle, getCKAValueAttrList, true);

            try {
                cerID = (byte[]) getCKAValueAttrList[0].pValue;
            } catch (Exception e) {
                return null;
            }

            ID = new String(cerID);

            return ID;
        } catch (PKCS11Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String getContainerByID(String KeyID) {
        try {
            String ID = null;
            PKCS11 ModuleP11 = module_.getPKCS11Module();
            CK_ATTRIBUTE[] findCerAttrList = new CK_ATTRIBUTE[1];
            findCerAttrList[0] = new CK_ATTRIBUTE();
            findCerAttrList[0].type = PKCS11Constants.CKA_CLASS;
            findCerAttrList[0].pValue = new Long(PKCS11Constants.CKO_PUBLIC_KEY);

            ModuleP11.C_FindObjectsInit(session_.getSessionHandle(), findCerAttrList, true);
            long[] CerHandle = ModuleP11.C_FindObjects(session_.getSessionHandle(), MAX_OBJS);
            ModuleP11.C_FindObjectsFinal(session_.getSessionHandle());

            if (CerHandle == null) {
                return null;
            }

            int num = CerHandle.length;
            if (num <= 0) {
                System.out.println("found: 0 publickey");
                return null;
            } else {
                System.out.println("found: " + num + " publickey");
            }

            byte[] cerID = null;
            for (int i = 0; i < num; i++) {
                CK_ATTRIBUTE[] getCKAValueAttrList = new CK_ATTRIBUTE[1];
                getCKAValueAttrList[0] = new CK_ATTRIBUTE();
                getCKAValueAttrList[0].type = PKCS11Constants.CKA_CONTAINER_NAME;

                ModuleP11.C_GetAttributeValue(session_.getSessionHandle(), CerHandle[i], getCKAValueAttrList, true);

                cerID = (byte[]) getCKAValueAttrList[0].pValue;

                ID = new String(cerID);
                System.out.println(ID);
            }
            return ID;
        } catch (PKCS11Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String genCSR(String KeyID, String DN) throws RFC2253NameParserException, InvalidKeyException, NoSuchAlgorithmException, SignatureException, TokenException, IOException {
        RSAPublicKey selectedPublicKey = getPublicKeyByID(KeyID);

        RSAPrivateKey privateSignatureKeyTemplate = new RSAPrivateKey();
        privateSignatureKeyTemplate.getSign().setBooleanValue(Boolean.TRUE);

        KeyAndCertificate selectedSignatureKeyAndCertificate = Util.selectKeyAndCertificate(
                session_, privateSignatureKeyTemplate, output_, input_, false, getObjectHandlePrivateKeyByID(KeyID));
        if (selectedSignatureKeyAndCertificate == null) {
            output_.println("We have no signature key to proceed. Finished.");
            output_.flush();
            throw new InvalidKeyException("No signature key found!");
        }

        iaik.pkcs.pkcs11.objects.PrivateKey selectedSignatureKey = (iaik.pkcs.pkcs11.objects.PrivateKey) selectedSignatureKeyAndCertificate
                .getKey();


        iaik.security.rsa.RSAPublicKey subjectPublicKey = new iaik.security.rsa.RSAPublicKey(new BigInteger(1, selectedPublicKey.getModulus().getByteArrayValue()),
                new BigInteger(1, selectedPublicKey.getPublicExponent().getByteArrayValue()));


        if (DN.indexOf("S=") != -1) {
            DN = DN.replace("S=", "ST=");
        }

        RFC2253NameParser subjectNameParser = new RFC2253NameParser(DN);
        Name subjectName = subjectNameParser.parse();

        CustomCertificateRequest certificateRequest = new CustomCertificateRequest(subjectPublicKey, subjectName);

        Signature tokenSignatureEngine = new PKCS11SignatureEngine("SHA1withRSA", session_,
                Mechanism.get(PKCS11Constants.CKM_RSA_PKCS), AlgorithmID.sha1);
        AlgorithmIDAdapter pkcs11Sha1RSASignatureAlgorithmID = new AlgorithmIDAdapter(
                AlgorithmID.sha1WithRSAEncryption);
        pkcs11Sha1RSASignatureAlgorithmID.setSignatureInstance(tokenSignatureEngine);

        java.security.PrivateKey tokenSignatureKey = new TokenPrivateKey(selectedSignatureKey);
        System.out.println("signing certificate request...");
        if (pkcs11Sha1RSASignatureAlgorithmID == null || tokenSignatureKey == null) {
            System.out.println("Key null");
        }
        certificateRequest.sign(pkcs11Sha1RSASignatureAlgorithmID, tokenSignatureKey);
        System.out.println("finished");
        byte[] raw_csr = certificateRequest.toByteArray();

        String csr = DatatypeConverter.printBase64Binary(raw_csr);
        System.out.println("-----BEGIN NEW CERTIFICATE REQUEST-----");
        System.out.println(csr);
        System.out.println("-----END NEW CERTIFICATE REQUEST-----");
        return "-----BEGIN NEW CERTIFICATE REQUEST-----" + "\n" + csr + "\n" + "-----END NEW CERTIFICATE REQUEST-----";
    }

    public static void importCertificate(String certData) throws CertificateException, NoSuchProviderException, FileNotFoundException, TokenException, NoSuchAlgorithmException, UnsupportedAttributeException {
        AccessController.doPrivileged(new PrivilegedAction() {
            public Object run() {
                Security.addProvider(new IAIK());
                // try if we have the ECC provider available, if yes, add it
                try {
                    Class eccProviderClass = Class.forName("iaik.security.ecc.provider.ECCProvider");
                    Provider eccProvider = (Provider) eccProviderClass.newInstance();
                    Security.addProvider(eccProvider);
                } catch (Exception ex) {
                    // ignore, we only need it for pkcs#12 files containing ECC keys
                }
                return null;
            }
        });

        //  parse certificate
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509",
                "IAIK");

        byte[] raw_cert = certData.getBytes();
        InputStream fileInputStream = new ByteArrayInputStream(raw_cert);

        //FileInputStream fileInputStream = new FileInputStream(certData);
        Collection certificateChain = certificateFactory.generateCertificates(fileInputStream);
        if (certificateChain.size() < 1) {
            output_.println("Did not find any certificate in the given input file. Finished.");
            output_.flush();
            throw new CertificateException("No certificate found!");
        }
        iaik.x509.X509Certificate x509Certificate = (iaik.x509.X509Certificate) certificateChain
                .iterator().next();
        certificateChain.remove(x509Certificate);

        output_
                .println("################################################################################");

        output_
                .println("################################################################################");
        output_.println("Searching for corresponding private key on token.");

        PublicKey publicKey = x509Certificate.getPublicKey();

        Object searchTemplate = null;
        if (publicKey.getAlgorithm().equalsIgnoreCase("RSA")) {
            java.security.interfaces.RSAPublicKey rsaPublicKey = (java.security.interfaces.RSAPublicKey) publicKey;
            RSAPrivateKey rsaPrivateKeySearchTemplate = new RSAPrivateKey();
            byte[] modulus = iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(rsaPublicKey
                    .getModulus());
            rsaPrivateKeySearchTemplate.getModulus().setByteArrayValue(modulus);
            searchTemplate = rsaPrivateKeySearchTemplate;
        } else if (publicKey.getAlgorithm().equalsIgnoreCase("DSA")) {
            java.security.interfaces.DSAPublicKey dsaPublicKey = (java.security.interfaces.DSAPublicKey) publicKey;
            DSAParams dsaParams = dsaPublicKey.getParams();
            DSAPrivateKey dsaPrivateKeySearchTemplate = new DSAPrivateKey();
            byte[] g = iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(dsaParams.getG());
            byte[] p = iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(dsaParams.getP());
            byte[] q = iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(dsaParams.getQ());
            dsaPrivateKeySearchTemplate.getBase().setByteArrayValue(g);
            dsaPrivateKeySearchTemplate.getPrime().setByteArrayValue(p);
            dsaPrivateKeySearchTemplate.getSubprime().setByteArrayValue(q);
            searchTemplate = dsaPrivateKeySearchTemplate;
        } else if (publicKey.getAlgorithm().equalsIgnoreCase("DH")
                || publicKey.getAlgorithm().equalsIgnoreCase("DiffieHellman")) {
            javax.crypto.interfaces.DHPublicKey dhPublicKey = (javax.crypto.interfaces.DHPublicKey) publicKey;
            DHParameterSpec dhParams = dhPublicKey.getParams();
            DHPrivateKey dhPrivateKeySearchTemplate = new DHPrivateKey();
            byte[] g = iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(dhParams.getG());
            byte[] p = iaik.pkcs.pkcs11.Util.unsignedBigIntergerToByteArray(dhParams.getP());
            dhPrivateKeySearchTemplate.getBase().setByteArrayValue(g);
            dhPrivateKeySearchTemplate.getPrime().setByteArrayValue(p);
            searchTemplate = dhPrivateKeySearchTemplate;
        }

        byte[] objectID = null;
        Object tmp = null;
        if (searchTemplate != null) {
            session_.findObjectsInit(searchTemplate);
            Object[] foundKeyObjects = session_.findObjects(1);
            if (foundKeyObjects.length > 0) {
                tmp = foundKeyObjects[0];
                Key foundKey = (Key) foundKeyObjects[0];
                objectID = foundKey.getId().getByteArrayValue();
                output_.println("found a correponding key on the token: ");
                output_.println(foundKey);
            } else {
                output_.println("found no correponding key on the token.");
            }
            session_.findObjectsFinal();
        } else {
            output_.println("public key is neither RSA, DSA nor DH.");
        }

        output_
                .println("################################################################################");

        output_
                .println("################################################################################");
        output_.println("Create certificate object(s) on token.");

        iaik.x509.X509Certificate currentCertificate = x509Certificate; // start with user cert
        boolean importedCompleteChain = false;
        while (!importedCompleteChain) {
            // create certificate object template
            X509PublicKeyCertificate pkcs11X509PublicKeyCertificate = new X509PublicKeyCertificate();
            Name subjectName = (Name) currentCertificate.getSubjectDN();
            Name issuerName = (Name) currentCertificate.getIssuerDN();
            String subjectCommonName = subjectName.getRDN(ObjectID.commonName);
            String issuerCommonName = issuerName.getRDN(ObjectID.commonName);
            char[] label = (subjectCommonName + "'s "
                    + ((issuerCommonName != null) ? issuerCommonName + " " : "") + "Certificate")
                    .toCharArray();
            byte[] newObjectID;
            // if we need a new object ID, create one
            if (objectID == null) {
                if (publicKey instanceof java.security.interfaces.RSAPublicKey) {
                    newObjectID = ((java.security.interfaces.RSAPublicKey) publicKey).getModulus()
                            .toByteArray();
                    MessageDigest digest = MessageDigest.getInstance("SHA-1");
                    newObjectID = digest.digest(newObjectID);
                } else if (publicKey instanceof java.security.interfaces.DSAPublicKey) {
                    newObjectID = ((java.security.interfaces.DSAPublicKey) publicKey).getY()
                            .toByteArray();
                    MessageDigest digest = MessageDigest.getInstance("SHA-1");
                    newObjectID = digest.digest(newObjectID);
                } else {
                    newObjectID = currentCertificate.getFingerprint("SHA-1");
                }
            } else {
                // we already got one from a corresponding private key before
                newObjectID = objectID;
            }

            byte[] encodedSubject = ((Name) currentCertificate.getSubjectDN()).getEncoded();
            byte[] encodedIssuer = ((Name) currentCertificate.getIssuerDN()).getEncoded();

            // serial number should be an DER encoded ASN.1 integer
			/*
             INTEGER asn1Integer = new INTEGER(userCertificate.getSerialNumber());
             ByteArrayOutputStream buffer = new ByteArrayOutputStream();
             DerCoder.encodeTo(asn1Integer, buffer);
             pkcs11X509PublicKeyCertificate.getSerialNumber().setByteArrayValue(buffer.toByteArray());
             */
            // Netscape deviates from the standard here, for use with Netscape rather use
            pkcs11X509PublicKeyCertificate.getSetAttributes(tmp);
            byte[] serialNumber = currentCertificate.getSerialNumber().toByteArray();

            pkcs11X509PublicKeyCertificate.getToken().setBooleanValue(Boolean.TRUE);
            pkcs11X509PublicKeyCertificate.getPrivate().setBooleanValue(Boolean.FALSE);
            pkcs11X509PublicKeyCertificate.getLabel().setCharArrayValue(label);
            pkcs11X509PublicKeyCertificate.getId().setByteArrayValue(newObjectID);
            pkcs11X509PublicKeyCertificate.getSubject().setByteArrayValue(encodedSubject);
            pkcs11X509PublicKeyCertificate.getIssuer().setByteArrayValue(encodedIssuer);
            pkcs11X509PublicKeyCertificate.getSerialNumber().setByteArrayValue(serialNumber);
            pkcs11X509PublicKeyCertificate.getValue().setByteArrayValue(
                    currentCertificate.getEncoded());
            output_.println(pkcs11X509PublicKeyCertificate);
            output_
                    .println("________________________________________________________________________________");
            //session_.createObject(pkcs11X509PublicKeyCertificate);
//			
            CK_ATTRIBUTE[] attr = new CK_ATTRIBUTE[12];
            attr[0] = new CK_ATTRIBUTE();
            attr[0].type = PKCS11Constants.CKA_CLASS;
            attr[0].pValue = new Long(PKCS11Constants.CKO_CERTIFICATE);

            attr[1] = new CK_ATTRIBUTE();
            attr[1].type = PKCS11Constants.CKA_TOKEN;
            attr[1].pValue = new Boolean(PKCS11Constants.TRUE);

            attr[2] = new CK_ATTRIBUTE();
            attr[2].type = PKCS11Constants.CKA_PRIVATE;
            attr[2].pValue = new Boolean(PKCS11Constants.FALSE);

            attr[3] = new CK_ATTRIBUTE();
            attr[3].type = PKCS11Constants.CKA_MODIFIABLE;
            attr[3].pValue = new Boolean(PKCS11Constants.TRUE);

            attr[4] = new CK_ATTRIBUTE();
            attr[4].type = PKCS11Constants.CKA_LABEL;
            attr[4].pValue = (char[]) label;

            attr[5] = new CK_ATTRIBUTE();
            attr[5].type = PKCS11Constants.CKA_CERTIFICATE_TYPE;
            attr[5].pValue = new Long(PKCS11Constants.CKC_X_509);

            attr[6] = new CK_ATTRIBUTE();
            attr[6].type = PKCS11Constants.CKA_SUBJECT;
            attr[6].pValue = (byte[]) encodedSubject;

            attr[7] = new CK_ATTRIBUTE();
            attr[7].type = PKCS11Constants.CKA_ID;
            attr[7].pValue = (byte[]) newObjectID;

            attr[8] = new CK_ATTRIBUTE();
            attr[8].type = PKCS11Constants.CKA_ISSUER;
            attr[8].pValue = (byte[]) encodedIssuer;

            attr[9] = new CK_ATTRIBUTE();
            attr[9].type = PKCS11Constants.CKA_SERIAL_NUMBER;
            attr[9].pValue = (byte[]) serialNumber;

            attr[10] = new CK_ATTRIBUTE();
            attr[10].type = PKCS11Constants.CKA_VALUE;
            attr[10].pValue = (byte[]) currentCertificate.getEncoded();

            String ContainerName = getContainerByID(DatatypeConverter.printHexBinary(newObjectID));

            attr[11] = new CK_ATTRIBUTE();
            attr[11].type = PKCS11Constants.CKA_CONTAINER_NAME;
            attr[11].pValue = (char[]) ContainerName.toCharArray();

            deleteCertificateByID(DatatypeConverter.printHexBinary(newObjectID));


            PKCS11 ModuleP11 = module_.getPKCS11Module();
            ModuleP11.C_CreateObject(session_.getSessionHandle(), attr, true);

            if (certificateChain.size() > 0) {
                currentCertificate = (iaik.x509.X509Certificate) certificateChain.iterator()
                        .next();
                certificateChain.remove(currentCertificate);
                objectID = null; // do not use the same ID for other certificates
            } else {
                importedCompleteChain = true;
            }
        }
        output_
                .println("################################################################################");
    }

    public static void deleteCertificateByID(String CertID) throws PKCS11Exception {
        PKCS11 ModuleP11 = module_.getPKCS11Module();
        CK_ATTRIBUTE[] findCerAttrList = new CK_ATTRIBUTE[1];
        findCerAttrList[0] = new CK_ATTRIBUTE();
        findCerAttrList[0].type = PKCS11Constants.CKA_CLASS;
        findCerAttrList[0].pValue = new Long(PKCS11Constants.CKO_CERTIFICATE);

        ModuleP11.C_FindObjectsInit(session_.getSessionHandle(), findCerAttrList, true);
        long[] CerHandle = ModuleP11.C_FindObjects(session_.getSessionHandle(), MAX_OBJS);
        ModuleP11.C_FindObjectsFinal(session_.getSessionHandle());

        if (CerHandle == null) {
            System.out.println("Cert not found");
        }

        int num = CerHandle.length;
        if (num <= 0) {
            System.out.println("found: 0 certificate");
        } else {
            System.out.println("found: " + num + " certificates");

            for (int i = 0; i < CerHandle.length; i++) {
                byte[] cerID = null;
                CK_ATTRIBUTE[] getCKAValueAttrList = new CK_ATTRIBUTE[1];

                getCKAValueAttrList[0] = new CK_ATTRIBUTE();
                getCKAValueAttrList[0].type = PKCS11Constants.CKA_ID;

                ModuleP11.C_GetAttributeValue(session_.getSessionHandle(), CerHandle[i], getCKAValueAttrList, true);

                cerID = (byte[]) getCKAValueAttrList[0].pValue;
                System.out.println(DatatypeConverter.printHexBinary(cerID));
                if (CertID.compareTo(DatatypeConverter.printHexBinary(cerID)) == 0) {
                    System.out.println("Delete cert: " + DatatypeConverter.printHexBinary(cerID));
                    ModuleP11.C_DestroyObject(session_.getSessionHandle(), CerHandle[i]);
                }
            }
        }

    }
    /*REMOTE UNBLOCK PIN*/

    public static String genRN(String SN) {
        if (SN.compareTo("") == 0) {
            return null;
        }
        String RN = "";

        String tmp1 = SN.concat("#").concat(radom10ByteNumber());

        byte[] tmpByte = null;
        try {
            tmpByte = tmp1.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }
        byte[] tmpByteCRC32 = ComputeCRC(tmpByte);

        byte[] rv = new byte[tmpByte.length + tmpByteCRC32.length];
        System.arraycopy(tmpByte, 0, rv, 0, tmpByte.length);
        System.arraycopy(tmpByteCRC32, 0, rv, tmpByte.length, tmpByteCRC32.length);

        int x = (tmp1.length() + 4) % 8;
        int length = tmp1.length() + 4 + 8 - x;
        int numBlock = length / 8;

        byte[] dataRN = new byte[length];
        Arrays.fill(dataRN, (byte) (length - tmpByte.length - tmpByteCRC32.length));
        System.arraycopy(rv, 0, dataRN, 0, rv.length);

        byte[] block[] = new byte[length / 8][8];

        for (int i = 0; i < numBlock; i++) {
            System.arraycopy(dataRN, i * 8, block[i], 0, 8);
        }

        byte[] bt[] = new byte[length / 8][8];

        for (int i = 0; i < numBlock; i++) {
            try {
                bt[i] = encryptBlock(block[i]);
            } catch (InvalidKeyException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvalidKeySpecException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (BadPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }


        byte[] encTDES = new byte[length];

        for (int i = 0; i < numBlock; i++) {
            System.arraycopy(bt[i], 0, encTDES, i * 8, 8);
        }

        byte[] datatosend = new byte[length + 6];
        Arrays.fill(datatosend, (byte) 0);

        byte[] prefix = null;
        try {
            prefix = "ostt1_".getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        System.arraycopy(prefix, 0, datatosend, 0, prefix.length);
        System.arraycopy(encTDES, 0, datatosend, prefix.length, encTDES.length);

        RN = DatatypeConverter.printBase64Binary(datatosend);

        return RN;
    }

    public static String getSN(String RN) {
        if (RN.compareTo("") == 0) {
            return null;
        }

        String SN = "";

        byte[] tmp = DatatypeConverter.parseBase64Binary(RN);

        byte[] rawRN = new byte[tmp.length];
        System.arraycopy(tmp, 0, rawRN, 0, tmp.length);

        if ((tmp.length - 6) % 8 != 0) {
            return null;
        }

        int numBlock = (tmp.length - 6) / 8;
        int length = (tmp.length - 6);

        byte[] block[] = new byte[numBlock][8];
        byte[] bt[] = new byte[numBlock][8];
        int n = 6;
        for (int i = 0; i < numBlock; i++) {
            System.arraycopy(rawRN, n, block[i], 0, 8);
            n += 8;
        }

        for (int i = 0; i < numBlock; i++) {
            try {
                bt[i] = decryptBlock(block[i]);
            } catch (InvalidKeyException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvalidKeySpecException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (BadPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }


        byte[] decRawRN = new byte[length];

        for (int i = 0; i < numBlock; i++) {
            System.arraycopy(bt[i], 0, decRawRN, i * 8, 8);
        }

        int last_byte = decRawRN[length - 1];

        byte[] temp = new byte[length - last_byte];

        System.arraycopy(decRawRN, 0, temp, 0, length - last_byte);

        byte[] B = ComputeCRC(temp);

        if (!Arrays.equals(B, CRC32OK)) {
            System.out.println("Checksum RN fail!");
            return null;
        }

        String temp1[] = null;
        try {
            temp1 = new String(decRawRN, "UTF-8").split("#");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        SN = temp1[0];

        return SN;
    }

    public static String genUC(String PIN, String RN) {
        if (PIN.compareTo("") == 0 || RN.compareTo("") == 0) {
            return null;
        }

        String UC = "";

        String tmp = PIN.concat("#").concat(RN);
        System.out.println("debug: " + tmp);
        byte[] RawTmp = null;
        try {
            RawTmp = tmp.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e1) {
            e1.printStackTrace();
        }
        byte[] CRC32A = ComputeCRC(RawTmp);

        byte[] rv = new byte[RawTmp.length + CRC32A.length];
        System.arraycopy(RawTmp, 0, rv, 0, RawTmp.length);
        System.arraycopy(CRC32A, 0, rv, RawTmp.length, CRC32A.length);

        int x = (tmp.length() + 4) % 8;
        int length = tmp.length() + 4 + 8 - x;
        int numBlock = length / 8;

        byte[] dataUC = new byte[length];
        Arrays.fill(dataUC, (byte) (length - RawTmp.length - CRC32A.length));
        System.arraycopy(rv, 0, dataUC, 0, rv.length);

        byte[] block[] = new byte[length / 8][8];

        for (int i = 0; i < numBlock; i++) {
            System.arraycopy(dataUC, i * 8, block[i], 0, 8);
        }
        byte[] bt[] = new byte[length / 8][8];

        for (int i = 0; i < numBlock; i++) {
            try {
                bt[i] = encryptBlock(block[i]);
            } catch (InvalidKeyException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvalidKeySpecException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (BadPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        byte[] encTDES = new byte[length];

        for (int i = 0; i < numBlock; i++) {
            System.arraycopy(bt[i], 0, encTDES, i * 8, 8);
        }

        UC = DatatypeConverter.printBase64Binary(encTDES);
        return UC;
    }

    public static String getSO(String UC) {
        if (UC.compareTo("") == 0) {
            return null;
        }

        String SO = "";

        byte[] tmp = DatatypeConverter.parseBase64Binary(UC);

        byte[] RawSO = new byte[tmp.length];
        System.arraycopy(tmp, 0, RawSO, 0, tmp.length);

        if ((tmp.length % 8) != 0) {
            return null;
        }

        int length = tmp.length;
        int numBlock = length / 8;

        byte[] block[] = new byte[numBlock][8];
        byte[] bt[] = new byte[numBlock][8];

        for (int i = 0; i < numBlock; i++) {
            System.arraycopy(RawSO, i * 8, block[i], 0, 8);
        }

        for (int i = 0; i < numBlock; i++) {
            try {
                bt[i] = decryptBlock(block[i]);
            } catch (InvalidKeyException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvalidKeySpecException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (BadPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        byte[] decRawUC = new byte[length];
        Arrays.fill(decRawUC, (byte) 0);

        for (int i = 0; i < numBlock; i++) {
            System.arraycopy(bt[i], 0, decRawUC, i * 8, 8);
        }

        int last_byte = decRawUC[length - 1];

        byte[] temp1 = new byte[length - last_byte];
        System.arraycopy(decRawUC, 0, temp1, 0, length - last_byte);

        byte[] B = ComputeCRC(temp1);

        if (!Arrays.equals(B, CRC32OK)) {
            System.out.println("Checksum UC fail!");
            return null;
        }
        byte[] temp2 = new byte[temp1.length - 4];
        System.arraycopy(temp1, 0, temp2, 0, temp1.length - 4);

        try {
            String temp3 = new String(temp2, "UTF-8");
            String temp4[] = temp3.split("#");
            System.out.println(temp4[1]);


            String a = "TT_b3N0dDFfnsnfPRdvlzZ0ikHdTpm/HusantaCEQsdM5yzo4HQl/c=";
            System.out.println(a.substring(3));




            return temp4[0];
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return "-1";
    }

    public static String decodeSOPIN(String encSOPIN) {
        String SO = "";
        if (encSOPIN.compareTo("") == 0) {
            return null;
        }
        byte[] rawSO = DatatypeConverter.parseBase64Binary(encSOPIN);
        if ((rawSO.length % 8) != 0) {
            return null;
        }
        int length = rawSO.length;
        int numBlock = length / 8;

        byte[] block[] = new byte[numBlock][8];
        byte[] bt[] = new byte[numBlock][8];

        for (int i = 0; i < numBlock; i++) {
            System.arraycopy(rawSO, i * 8, block[i], 0, 8);
        }

        for (int i = 0; i < numBlock; i++) {
            try {
                bt[i] = decryptBlock(block[i]);
            } catch (InvalidKeyException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvalidKeySpecException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (BadPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }

        byte[] decRawSO = new byte[length];
        Arrays.fill(decRawSO, (byte) 0);

        for (int i = 0; i < numBlock; i++) {
            System.arraycopy(bt[i], 0, decRawSO, i * 8, 8);
        }
        int last_byte = decRawSO[length - 1];
        byte[] temp = new byte[length - last_byte];
        System.arraycopy(decRawSO, 0, temp, 0, length - last_byte);

        try {
            SO = new String(temp, "UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }
        return SO;
    }

    public static String encodeSOPIN(String SoPin) {
        if (SoPin.compareTo("") == 0) {
            return null;
        }
        byte[] rawSo = null;
        try {
            rawSo = SoPin.getBytes("UTF-8");
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        }

        int x, length, numBlock;
        String SOPIN = "";

        x = rawSo.length % 8;
        length = rawSo.length + 8 - x;
        numBlock = length / 8;

        byte[] dataSO = new byte[length];
        Arrays.fill(dataSO, (byte) (length - SoPin.length()));
        System.arraycopy(rawSo, 0, dataSO, 0, rawSo.length);

        byte[] block[] = new byte[numBlock][8];
        for (int i = 0; i < numBlock; i++) {
            System.arraycopy(dataSO, i * 8, block[i], 0, 8);
        }
        byte[] bt[] = new byte[numBlock][8];

        for (int i = 0; i < numBlock; i++) {
            try {
                bt[i] = encryptBlock(block[i]);
            } catch (InvalidKeyException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (InvalidKeySpecException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchAlgorithmException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (NoSuchPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalBlockSizeException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (BadPaddingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (UnsupportedEncodingException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        byte[] encSOPIN = new byte[length];

        for (int i = 0; i < numBlock; i++) {
            System.arraycopy(bt[i], 0, encSOPIN, i * 8, 8);
        }

        SOPIN = DatatypeConverter.printBase64Binary(encSOPIN);

        return SOPIN;
    }

    public static byte[] encryptBlock(byte[] block) throws InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
        if (block.length != 8) {
            return null;
        }

        String key1 = "12345678";
        DESKeySpec KEY1 = new DESKeySpec(key1.getBytes("UTF-8"));
        SecretKeyFactory keyFactory1 = SecretKeyFactory.getInstance("DES");
        SecretKey myDesKey1 = keyFactory1.generateSecret(KEY1);

        String key2 = "90abcdef";
        DESKeySpec KEY2 = new DESKeySpec(key2.getBytes("UTF-8"));
        SecretKeyFactory keyFactory2 = SecretKeyFactory.getInstance("DES");
        SecretKey myDesKey2 = keyFactory2.generateSecret(KEY2);

        Cipher desCipher1;
        desCipher1 = Cipher.getInstance("DES/ECB/NoPadding");

        desCipher1.init(Cipher.ENCRYPT_MODE, myDesKey1);

        Cipher desCipher2;
        desCipher2 = Cipher.getInstance("DES/ECB/NoPadding");

        desCipher2.init(Cipher.DECRYPT_MODE, myDesKey2);

        byte[] d3 = desCipher1.doFinal(block);

        byte[] d2 = desCipher2.doFinal(d3);

        byte[] d1 = desCipher1.doFinal(d2);

        return d1;
    }

    public static byte[] decryptBlock(byte[] block) throws InvalidKeyException, InvalidKeySpecException, NoSuchAlgorithmException, NoSuchPaddingException, IllegalBlockSizeException, BadPaddingException, UnsupportedEncodingException {
        if (block.length != 8) {
            return null;
        }

        String key1 = "12345678";
        DESKeySpec KEY1 = new DESKeySpec(key1.getBytes("UTF-8"));
        SecretKeyFactory keyFactory1 = SecretKeyFactory.getInstance("DES");
        SecretKey myDesKey1 = keyFactory1.generateSecret(KEY1);

        String key2 = "90abcdef";
        DESKeySpec KEY2 = new DESKeySpec(key2.getBytes("UTF-8"));
        SecretKeyFactory keyFactory2 = SecretKeyFactory.getInstance("DES");
        SecretKey myDesKey2 = keyFactory2.generateSecret(KEY2);

        Cipher desCipher1;
        desCipher1 = Cipher.getInstance("DES/ECB/NoPadding");

        desCipher1.init(Cipher.DECRYPT_MODE, myDesKey1);

        Cipher desCipher2;
        desCipher2 = Cipher.getInstance("DES/ECB/NoPadding");

        desCipher2.init(Cipher.ENCRYPT_MODE, myDesKey2);

        byte[] d3 = desCipher1.doFinal(block);

        byte[] d2 = desCipher2.doFinal(d3);

        byte[] d1 = desCipher1.doFinal(d2);

        return d1;
    }

    public static long UpdateCRC(byte b, long crc) {
        long TabVal = (crc ^ b) & 0xffL;
        for (int i = 8; i > 0; i--) {
            if ((TabVal % 2) == 1) {
                TabVal = (TabVal >> 1) ^ 0xedb88320L;
            } else {
                TabVal = TabVal >> 1;
            }
        }

        return (TabVal ^ ((crc >> 8) & 0x00ffffffL));
    }

    public static byte[] ComputeCRC(byte[] bytes) {
        byte[] result = new byte[4];

        long res = 0xffffffffL;
        for (int i = 0; i < bytes.length; i++) {
            res = UpdateCRC(bytes[i], res);
        }
        result[0] = (byte) (res & 0xffL);
        result[1] = (byte) (res >> 8);
        result[2] = (byte) (res >> 16);
        result[3] = (byte) (res >> 24);
        return result;
    }

    public static String radom10ByteNumber() {
        int START = 48;
        int END = 57;
        String result = "";
        Random random = new Random();
        for (int idx = 1; idx <= 10; ++idx) {
            result += (char) showRandomInteger(START, END, random);
        }
        return result;
    }

    private static int showRandomInteger(int aStart, int aEnd, Random aRandom) {
        if (aStart > aEnd) {
            throw new IllegalArgumentException("Start cannot exceed End.");
        }
        //get the range, casting to long to avoid overflow problems
        long range = (long) aEnd - (long) aStart + 1;
        // compute a fraction of the range, 0 <= frac < range
        long fraction = (long) (range * aRandom.nextDouble());
        int randomNumber = (int) (fraction + aStart);
        return randomNumber;
    }

    public static String getStringfilter(String str) {
        char[] c_str = str.toCharArray();
        int i;
        for (i = 0; i < str.length(); i++) {
            int i_str = c_str[i];
            if (i_str < 33 || i_str > 126) {
                break;
            }
        }
        return str.substring(0, i);
    }
}